package com.ideal.license.verifier.manager;

import com.alibaba.fastjson.JSON;
import com.ideal.license.core.exception.CheckParamException;
import com.ideal.license.core.model.HardWarePercent;
import com.ideal.license.core.model.LicenseModel;
import com.ideal.license.core.util.HardWareUtils;
import com.ideal.license.core.util.LicenseManagerHolder;
import com.ideal.license.verifier.exception.CheckHardWareException;
import de.schlichtherle.license.*;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;
import java.util.prefs.Preferences;

public class LicenseVerify {
    private static final Logger logger = Logger.getLogger(LicenseVerify.class.getName());

    /**
     * 验证证书.
     * @param model
     * @return
     */
    public LicenseModel verfiy(VerifyModel model) throws Exception {
        return verfiy(model, true);
    }

    /**
     * 服务端验证.
     * @param model
     * @return
     * @throws Exception
     */
    public LicenseModel verfiyServer(VerifyModel model) throws Exception {
        return verfiy(model, false);
    }

    private LicenseModel verfiy(VerifyModel model, boolean isCheck) throws Exception {
        HardWarePercent percent = new HardWarePercent();
        checkParam(model);
        this.loadPercent(percent);
        this.checkPercent(percent);

        LicenseManager licenseManager = LicenseManagerHolder.getLicenseManager(initParam(model));
        licenseManager.install(new File(model.getLicPath()));
        logger.info("license install success");

        LicenseContent content = licenseManager.verify();
        LicenseModel licenseModel = (LicenseModel)content.getExtra();
        logger.info("license verfiy success");

        if (isCheck) {
            validateHardWare(licenseModel, percent);
            logger.info("check hardWare success");
        }

        return licenseModel;
    }

    /**
     * 初始化licenseParam.
     * @return
     */
    private LicenseParam initParam(VerifyModel model) {
        Preferences preferences = Preferences.systemNodeForPackage(this.getClass());
        CipherParam cipherParam = new DefaultCipherParam(model.getStorePass());
        KeyStoreParam keyStoreParam = new DefaultKeyStoreParam(this.getClass(),model.getPriPath(), model.getAlias(),
                model.getStorePass(), null, model.getKeyAlg());
        LicenseParam licenseParam = new DefaultLicenseParam(model.getSubject(), preferences, keyStoreParam, cipherParam);

        logger.info("init licenseParam success");

        return licenseParam;
    }

    /**
     * 验证参数.
     * @param model
     */
    private void checkParam(VerifyModel model) throws Exception {
        String[] algs = {"RSA", "DSA"};

        if (StringUtils.isBlank(model.getAlias())) {
            throw new CheckParamException("alias is null");
        }

        if (StringUtils.isBlank(model.getLicPath())) {
            throw new CheckParamException("licPath is null");
        }

        if (StringUtils.isBlank(model.getPriPath())) {
            throw new CheckParamException("priPath is null");
        }

        if (StringUtils.isBlank(model.getStorePass())) {
            throw new CheckParamException("storePass is null");
        }

        if (StringUtils.isBlank(model.getSubject())){
            throw new CheckParamException("subject is null");
        }

        if (StringUtils.isBlank(model.getKeyAlg())) {
            throw new CheckParamException("keyAlg is null");
        }

        if (!ArrayUtils.contains(algs, model.getKeyAlg())) {
            throw new CheckParamException("keyAlg can only be RSA or DSA");
        }

        File f = new File(model.getLicPath());
        if (!f.exists()) {
            throw new CheckParamException("lic file is not exist");
        }

        File store = new File(model.getPriPath());
        if (!store.exists()) {
            throw new CheckParamException("store file is not exist");
        }

        if (StringUtils.isBlank(model.getEdition())) {
            throw new CheckParamException("edition is null");
        }

        logger.info("check params success");
    }

    /**
     * 检测硬件信息.
     * @param model
     * @param percent
     * @throws CheckHardWareException
     */
    private void validateHardWare(LicenseModel model, HardWarePercent percent) throws CheckHardWareException {
        List<String> macs = HardWareUtils.getMacListLinux();
        List<String> ips = HardWareUtils.getIpListLinux();
        List<String> cpus = HardWareUtils.getCpuListLinux();
        List<String> disks = HardWareUtils.getDiskListLinux();
        String motherBoadSn = HardWareUtils.getMotherBoardSnLinux();
        String systemSn = HardWareUtils.getSystemSnLinux();

        if (StringUtils.isBlank(motherBoadSn)) {
            throw new CheckHardWareException("主板序列号没有检测到!");
        }

        // 检查主板序列号
        if (!motherBoadSn.equals(model.getBaseComputerModel().getMotherboardSN().trim())) {
            throw new CheckHardWareException("主板序列号：主机与license不一致!");
        }

        logger.info("motherboard check success");

        if (StringUtils.isBlank(systemSn)) {
            throw new CheckHardWareException("系统序列号没有检测到!");
        }

        // 检测 系统序列号
        if (!systemSn.equals(model.getBaseComputerModel().getSystemSN().trim())) {
            throw new CheckHardWareException("系统序列号：主机与license不一致!");
        }

        logger.info("system check success");

        // 检测cpu
        if (cpus.isEmpty()) {
            throw new CheckHardWareException("CPU没有检测到!");
        }

        String cpu = model.getBaseComputerModel().getCPUSerial();

        if (StringUtils.isBlank(cpu)) {
            throw new CheckHardWareException("license文件损坏!");
        }

        List<String> cpuList = Arrays.asList(cpu.split(","));
        cpus.retainAll(cpuList);
        double cpuPercent = cpus.size() * 100 / cpuList.size();

        if (cpuPercent < percent.getCpuPercent()) {
            throw new CheckHardWareException("CPU SN:主机与licesne匹配小于" + percent.getCpuPercent());
        }

        logger.info("cpu check success");

        // mac 检测
        if (macs.isEmpty()) {
            throw new CheckHardWareException("MAC没有检测到!");
        }

        String modeMac = model.getBaseComputerModel().getIpMacAddress();
        if (StringUtils.isBlank(modeMac)) {
            throw new CheckHardWareException("license文件损坏!");
        }

        List<String> macList = Arrays.asList(modeMac.split(","));
        macs.retainAll(macList);
        double macPercent = macs.size() * 100/macList.size();
        if (macPercent < percent.getMacPercent()) {
            throw new CheckHardWareException("mac地址:主机与licesne匹配小于" + percent.getMacPercent());
        }

        logger.info("mac check success");

        // 硬盘检测
        if (disks.isEmpty()) {
            throw new CheckHardWareException("DISK没有检测到!");
        }

        String modeDisk = model.getBaseComputerModel().getHardDiskSN();
        if (StringUtils.isBlank(modeDisk)) {
            throw new CheckHardWareException("license文件损坏!");
        }

        List<String> diskList = Arrays.asList(modeDisk.split(","));
        disks.retainAll(diskList);
        double diskPercent = disks.size() * 100 / diskList.size();
        if (diskPercent < percent.getDiskPercent()) {
            throw new CheckHardWareException("diskSN:主机与licesne匹配小于" + percent.getDiskPercent());
        }

        logger.info("disk check success");

        // ip检测
        if (ips.isEmpty()) {
            throw new CheckHardWareException("IP没有检测到!");
        }

        String modelIp = model.getBaseComputerModel().getIpAddress();
        if (StringUtils.isBlank(modelIp)) {
            throw new CheckHardWareException("license文件损坏!");
        }

        List<String> ipList = Arrays.asList(modelIp.split(","));
        ips.retainAll(ipList);
        double ipPercent = ips.size() * 100 / ipList.size();
        if (ipPercent < percent.getIpPercent()) {
            throw new CheckHardWareException("IP地址:主机与licesne匹配小于" + percent.getIpPercent());
        }

        logger.info("ip check success");
    }

    private void loadPercent(HardWarePercent percent) throws IOException {
        Properties prop = new Properties();
        prop.load(this.getClass().getResourceAsStream("/vp.properties"));
        String ip = prop.getProperty("IP");
        String disk = prop.getProperty("DISK");
        String mac = prop.getProperty("MAC");
        String cpu = prop.getProperty("CPU");

        percent.setDiskPercent(Double.valueOf(disk));
        percent.setIpPercent(Double.valueOf(ip));
        percent.setMacPercent(Double.valueOf(mac));
        percent.setCpuPercent(Double.valueOf(cpu));

        logger.info("load percent success");
    }

    private void checkPercent(HardWarePercent percent) throws CheckParamException {
        if (null == percent) {
            throw new CheckParamException("hardWare properties is null");
        }

        if (null == percent.getCpuPercent() || percent.getCpuPercent() <= 0) {
            throw new CheckParamException("CPU properties is null");
        }

        if (null == percent.getDiskPercent() || percent.getDiskPercent() <= 0) {
            throw new CheckParamException("disk properties is null");
        }

        if (null == percent.getIpPercent() || percent.getIpPercent() <= 0) {
            throw new CheckParamException("ip properties is null");
        }

        if (null == percent.getMacPercent() || percent.getMacPercent() <= 0) {
            throw new CheckParamException("mac properties is null");
        }

        logger.info("hardware check success");
    }

    private VerifyModel getWin(){
        VerifyModel model = new VerifyModel();
        model.setKeyAlg("RSA");
        model.setLicPath("D:\\key\\server\\20171016123057496.lic");
        model.setPriPath("D:\\key\\client\\feilongclient.keystore");
        model.setSubject("feilong");
        model.setStorePass("store123456");
        model.setEdition("普通版");
        model.setAlias("feilong");

        return model;
    }

    private VerifyModel getLin() {
        VerifyModel model = new VerifyModel();
        model.setAlias("feilong");
        model.setKeyAlg("RSA");
        model.setLicPath("/usr/local/license/server/20171015125633838.lic");
        model.setPriPath("/usr/local/license/client/feilongclient.keystore");
        model.setSubject("feilong lic");
        model.setStorePass("store123456");
        model.setEdition("normal");

        return model;
    }

    public static void main(String[] args) {
        try {
            HardWarePercent percent = new HardWarePercent();
            new LicenseVerify().loadPercent(percent);

            System.out.println(JSON.toJSONString(percent));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
